package net.jgrm.product.controller;

import net.jgrm.product.entity.Product;
import net.jgrm.product.service.IProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;

/**
 * JetCache 功能测试控制器
 * 用于验证 JetCache 两级缓存在高并发场景下的性能表现
 */
@RestController
@RequestMapping("/jetcache-test")
public class JetCacheTestController {

    @Autowired
    private IProductService productService;

    private final ExecutorService executorService = Executors.newFixedThreadPool(20);

    /**
     * 高并发缓存读取测试
     * 测试 JetCache @Cached 注解的并发性能
     */
    @GetMapping("/concurrent-read/{productId}")
    public Map<String, Object> testConcurrentRead(@PathVariable Long productId,
                                                  @RequestParam(defaultValue = "10") int threadCount) {
        Map<String, Object> result = new HashMap<>();

        long startTime = System.currentTimeMillis();

        // 并发读取测试
        CompletableFuture<Product>[] futures = IntStream.range(0, threadCount)
                .mapToObj(i -> CompletableFuture.supplyAsync(() -> {
                    try {
                        return productService.getProductById(productId);
                    } catch (Exception e) {
                        return null;
                    }
                }, executorService))
                .toArray(CompletableFuture[]::new);

        // 等待所有线程完成
        CompletableFuture.allOf(futures).join();

        long endTime = System.currentTimeMillis();

        result.put("testType", "JetCache 并发读取测试");
        result.put("productId", productId);
        result.put("threadCount", threadCount);
        result.put("executionTime", endTime - startTime);
        result.put("success", true);
        result.put("message", "JetCache 并发读取测试完成，应该从两级缓存中快速返回数据");

        return result;
    }

    /**
     * 缓存更新测试
     * 测试 JetCache @CacheUpdate 注解的功能
     */
    @PostMapping("/cache-update-test/{productId}")
    public Map<String, Object> testCacheUpdate(@PathVariable Long productId,
                                               @RequestParam String newProductName) {
        Map<String, Object> result = new HashMap<>();

        try {
            // 先读取一次确保缓存中有数据
            Product originalProduct = productService.getProductById(productId);

            // 更新商品信息
            Product updatedProduct = new Product();
            updatedProduct.setId(productId);
            updatedProduct.setProductName(newProductName);
            updatedProduct.setDescription("JetCache 缓存更新测试");
            updatedProduct.setPrice(new BigDecimal("199.99"));
            updatedProduct.setStock(originalProduct.getStock());
            updatedProduct.setStatus(1);

            Product resultProduct = productService.updateProductById(updatedProduct);

            result.put("testType", "JetCache 缓存更新测试");
            result.put("success", true);
            result.put("originalName", originalProduct.getProductName());
            result.put("updatedName", resultProduct.getProductName());
            result.put("message", "JetCache @CacheUpdate 注解自动更新缓存成功");

        } catch (Exception e) {
            result.put("success", false);
            result.put("error", e.getMessage());
        }

        return result;
    }

    /**
     * 缓存失效测试
     * 测试 JetCache @CacheInvalidate 注解的功能
     */
    @PostMapping("/cache-invalidate-test/{productId}")
    public Map<String, Object> testCacheInvalidate(@PathVariable Long productId,
                                                   @RequestParam(defaultValue = "5") int quantity) {
        Map<String, Object> result = new HashMap<>();

        try {
            // 先读取一次确保缓存中有数据
            Product beforeProduct = productService.getProductById(productId);

            // 减库存操作会触发 @CacheInvalidate
            boolean success = productService.decreaseStock(productId, quantity);

            // 再次读取，应该从数据库重新加载
            Product afterProduct = productService.getProductById(productId);

            result.put("testType", "JetCache 缓存失效测试");
            result.put("success", success);
            result.put("beforeStock", beforeProduct.getStock());
            result.put("afterStock", afterProduct.getStock());
            result.put("decreasedQuantity", quantity);
            result.put("message", "JetCache @CacheInvalidate 注解自动删除缓存成功");

        } catch (Exception e) {
            result.put("success", false);
            result.put("error", e.getMessage());
        }

        return result;
    }

    /**
     * 缓存穿透防护测试
     * 测试对不存在数据的并发访问
     */
    @GetMapping("/cache-penetration-test")
    public Map<String, Object> testCachePenetration(@RequestParam(defaultValue = "999999") Long nonExistentId,
                                                    @RequestParam(defaultValue = "10") int threadCount) {
        Map<String, Object> result = new HashMap<>();

        long startTime = System.currentTimeMillis();

        // 并发访问不存在的数据
        CompletableFuture<Product>[] futures = IntStream.range(0, threadCount)
                .mapToObj(i -> CompletableFuture.supplyAsync(() -> {
                    try {
                        return productService.getProductById(nonExistentId);
                    } catch (Exception e) {
                        return null; // 预期会抛出"商品不存在"异常
                    }
                }, executorService))
                .toArray(CompletableFuture[]::new);

        CompletableFuture.allOf(futures).join();

        long endTime = System.currentTimeMillis();

        result.put("testType", "JetCache 缓存穿透防护测试");
        result.put("nonExistentId", nonExistentId);
        result.put("threadCount", threadCount);
        result.put("executionTime", endTime - startTime);
        result.put("success", true);
        result.put("message", "JetCache 自动防止缓存穿透，应该只查询一次数据库");

        return result;
    }

    /**
     * 创建测试数据
     */
    @PostMapping("/create-test-product")
    public Map<String, Object> createTestProduct() {
        Map<String, Object> result = new HashMap<>();

        try {
            Product product = new Product();
            product.setProductName("JetCache测试商品");
            product.setDescription("用于测试JetCache两级缓存的商品");
            product.setPrice(new BigDecimal("299.99"));
            product.setStock(1000);
            product.setStatus(1);

            Product savedProduct = productService.saveProduct(product);

            result.put("testType", "创建JetCache测试数据");
            result.put("success", true);
            result.put("productId", savedProduct.getId());
            result.put("productName", savedProduct.getProductName());
            result.put("message", "JetCache测试商品创建成功，@CacheUpdate自动缓存新数据");

        } catch (Exception e) {
            result.put("success", false);
            result.put("error", e.getMessage());
        }

        return result;
    }

    /**
     * JetCache 性能对比测试
     */
    @GetMapping("/performance-test/{productId}")
    public Map<String, Object> performanceTest(@PathVariable Long productId,
                                               @RequestParam(defaultValue = "100") int iterations) {
        Map<String, Object> result = new HashMap<>();

        // 预热缓存
        productService.getProductById(productId);

        long startTime = System.currentTimeMillis();

        // 连续读取测试
        for (int i = 0; i < iterations; i++) {
            productService.getProductById(productId);
        }

        long endTime = System.currentTimeMillis();

        result.put("testType", "JetCache 性能测试");
        result.put("productId", productId);
        result.put("iterations", iterations);
        result.put("executionTime", endTime - startTime);
        result.put("avgTimePerRequest", (double) (endTime - startTime) / iterations);
        result.put("success", true);
        result.put("message", "JetCache 两级缓存性能测试完成，大部分请求应该从本地Caffeine缓存返回");

        return result;
    }
}